home *** CD-ROM | disk | FTP | other *** search
/ Delphi 5 for Professionals / DELPHI5.iso / AddOns / Components / TEECHART / Src Code / TEEDATA.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-10-24  |  13.5 KB  |  489 lines

  1. {****************************************}
  2. {  TeeChart Series DB Virtual DataSet    }
  3. { Copyright (c) 1996-98 by David Berneda }
  4. {          All Rights Reserved           }
  5. {****************************************}
  6. {$I teedefs.inc}
  7. unit TeeData;
  8.  
  9. { This unit contains a VIRTUAL DATASET component for Delphi 3 or 4
  10.  
  11.   The TSeriesDataSet component is an intermediary between a
  12.   Series component and a TDataSource.
  13.  
  14.   You can show Series values in a DBGrid, for example:
  15.  
  16.   SeriesDataSet1.Series := Series1;
  17.   DataSource1.DataSet   := SeriesDataSet1;
  18.   DBGrid1.DataSource    := DataSource1;
  19.  
  20.   To refresh data:
  21.  
  22.   SeriesDataSet1.Close;
  23.   Series1.Add(....)
  24.   SeriesDataSet1.Open;
  25.  
  26.   Additional information under Delphi 3 or 4 \Demos\TextData
  27.   
  28. }
  29. interface
  30.  
  31. uses DB,Classes,Teengine,Graphics;
  32.  
  33. Const MaxLabelLen=128;
  34.  
  35. type
  36.   PFloat=^Double;
  37.   PSeriesPoint=^TSeriesPoint;
  38.   TSeriesPoint=packed record
  39.     Color:TColor;
  40.     X:Double;
  41.     Values:Array[0..10] of Double;
  42.     ALabel:String[MaxLabelLen];
  43.   end;
  44.  
  45.   PRecInfo = ^TRecInfo;
  46.   TRecInfo = packed record
  47.     Bookmark: Integer;
  48.     BookmarkFlag: TBookmarkFlag;
  49.   end;
  50.  
  51. { TSeriesDataSet }
  52.  
  53.   TSeriesDataSet = class(TDataSet)
  54.   private
  55.     FSeries: TChartSeries;
  56.     FBookMarks:TList;
  57.     FCurRec: Integer;
  58.     FLastBookmark: Integer;
  59.     Function RecInfoOfs: Integer;
  60.     Function RecBufSize: Integer;
  61.     Procedure DoCreateField(Const AFieldName:String; AType:TFieldType; ASize:Integer);
  62.   protected
  63.     { Overriden abstract methods (required) }
  64.     function AllocRecordBuffer: PChar; override;
  65.     procedure FreeRecordBuffer(var Buffer: PChar); override;
  66.     procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override;
  67.     function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override;
  68.     function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;
  69.     function GetRecordSize: Word; override;
  70.     procedure InternalAddRecord(Buffer: Pointer; Append: Boolean); override;
  71.     procedure InternalClose; override;
  72.     procedure InternalDelete; override;
  73.     procedure InternalFirst; override;
  74.     procedure InternalGotoBookmark(Bookmark: Pointer); override;
  75.     procedure InternalHandleException; override;
  76.     procedure InternalInitFieldDefs; override;
  77.     procedure InternalInitRecord(Buffer: PChar); override;
  78.     procedure InternalLast; override;
  79.     procedure InternalOpen; override;
  80.     procedure InternalPost; override;
  81.     procedure InternalSetToRecord(Buffer: PChar); override;
  82.     function IsCursorOpen: Boolean; override;
  83.     procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override;
  84.     procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override;
  85.     procedure SetFieldData(Field: TField; Buffer: Pointer); override;
  86.  
  87.     { Additional overrides (optional) }
  88.     function GetRecordCount: Integer; override;
  89.     function GetRecNo: Integer; override;
  90.     procedure SetRecNo(Value: Integer); override;
  91.     Procedure SetSeries(ASeries:TChartSeries); virtual;
  92.     Procedure AddSeriesPoint(Buffer:Pointer; ABookMark:Integer); virtual;
  93.   public
  94.     function GetFieldData(Field: TField; Buffer: Pointer): Boolean; override;
  95.     procedure Notification( AComponent: TComponent;
  96.                             Operation: TOperation); override;
  97.   published
  98.     property Series: TChartSeries read FSeries write SetSeries stored True;
  99.     property Active;
  100.   end;
  101.  
  102. implementation
  103.  
  104. uses Windows, SysUtils, Forms,TeeProco,TeCanvas;
  105.  
  106. { TSeriesDataSet }
  107. Procedure TSeriesDataSet.SetSeries(ASeries:TChartSeries);
  108. Var WasActive:Boolean;
  109. begin
  110.   {$IFDEF TEETRIAL}
  111.   TeeTrial(ComponentState);
  112.   {$ENDIF}
  113.   WasActive:=Active;
  114.   Active:=False;
  115.   FSeries:=ASeries;
  116.   {$IFNDEF D1}
  117.   if Assigned(FSeries) then FSeries.FreeNotification(Self);
  118.   {$ENDIF}
  119.   if Assigned(FSeries) and WasActive then Active:=True;
  120. end;
  121.  
  122. procedure TSeriesDataSet.Notification( AComponent: TComponent;
  123.                             Operation: TOperation);
  124. begin
  125.   inherited Notification(AComponent, Operation);
  126.   if Operation=opRemove then
  127.   begin
  128.     if Assigned(FSeries) and (AComponent=FSeries) then
  129.        SetSeries(nil);
  130.   end;
  131. end;
  132.  
  133. Function TSeriesDataSet.RecInfoOfs:Integer;
  134. begin
  135.   result:= SizeOf(TSeriesPoint);
  136. end;
  137.  
  138. Function TSeriesDataSet.RecBufSize: Integer;
  139. begin
  140.   result:=RecInfoOfs + SizeOf(TRecInfo);
  141. end;
  142.  
  143. procedure TSeriesDataSet.InternalOpen;
  144. var I: Integer;
  145. begin
  146.   if not Assigned(FSeries) then Raise Exception.Create('No Series assigned!');
  147.   { Fabricate integral bookmark values }
  148.   FBookMarks:=TList.Create;
  149.   for I := 1 to FSeries.Count do FBookMarks.Add(Pointer(I));
  150.   FLastBookmark := FSeries.Count;
  151.  
  152.   FCurRec := -1;
  153.  
  154.   BookmarkSize := SizeOf(Integer);
  155.  
  156.   InternalInitFieldDefs;
  157.   if DefaultFields then CreateFields;
  158.   BindFields(True);
  159. end;
  160.  
  161. procedure TSeriesDataSet.InternalClose;
  162. begin
  163.   FBookMarks.Free;
  164.   FBookMarks:=nil;
  165.   if DefaultFields then DestroyFields;
  166.   FLastBookmark := 0;
  167.   FCurRec := -1;
  168. end;
  169.  
  170. function TSeriesDataSet.IsCursorOpen: Boolean;
  171. begin
  172.   Result := Assigned(FSeries);
  173. end;
  174.  
  175. Procedure TSeriesDataSet.DoCreateField(Const AFieldName:String; AType:TFieldType; ASize:Integer);
  176. begin
  177.   {$IFDEF C3D4}
  178.   With TFieldDef.Create(FieldDefs) do
  179.   begin
  180.     Name      := AFieldName;
  181.     Size      := ASize;
  182.     Required  := False;
  183.     DataType  := AType;
  184.   end;
  185.   {$ELSE}
  186.   TFieldDef.Create(FieldDefs, AFieldName, AType, ASize, False, FieldDefs.Count+1)
  187.   {$ENDIF}
  188. end;
  189.  
  190. procedure TSeriesDataSet.InternalInitFieldDefs;
  191.  
  192.   Function GetFieldName(Const ADefault,AName:String):String;
  193.   begin
  194.     if AName='' then result:=ADefault
  195.                 else result:=AName;
  196.   end;
  197.  
  198.   Procedure AddField(IsDateTime:Boolean; Const FieldName:String);
  199.   begin
  200.     if IsDateTime then DoCreateField(FieldName,ftDateTime,0)
  201.                   else DoCreateField(FieldName,ftFloat,0);
  202.   end;
  203.  
  204. var tmp:String;
  205.     t:Integer;
  206. begin
  207.   FieldDefs.Clear;
  208.   if Assigned(FSeries) then
  209.   begin
  210.     {$IFDEF C3D4}
  211.     With TFieldDef.Create(FieldDefs) do
  212.     begin
  213.       Name:='Color';
  214.       DataType:=ftInteger;
  215.       Size:=0;
  216.       Required:=False;
  217.       FieldNo:=1;
  218.     end;
  219.     {$ELSE}
  220.     TFieldDef.Create(FieldDefs, 'Color', ftInteger, 0, False, 1);
  221.     {$ENDIF}
  222.     With FSeries.XValues do AddField(DateTime,GetFieldName('X',Name));
  223.     With FSeries.YValues do AddField(DateTime,GetFieldName('Y',Name));
  224.     {$IFDEF C3D4}
  225.     With TFieldDef.Create(FieldDefs) do
  226.     begin
  227.       Name:='Label';
  228.       DataType:=ftString;
  229.       Size:=MaxLabelLen;
  230.       Required:=False;
  231.       FieldNo:=4;
  232.     end;
  233.     {$ELSE}
  234.     TFieldDef.Create(FieldDefs, 'Label', ftString, MaxLabelLen, False, 4);
  235.     {$ENDIF}
  236.     for t:=2 to FSeries.ValuesLists.Count-1 do
  237.     With FSeries.ValuesLists.ValueList[t] do
  238.     begin
  239.       tmp:=Name;
  240.       if Name='' then tmp:='Value'+IntToStr(t)
  241.                  else tmp:=Name;
  242.       AddField(DateTime,tmp);
  243.     end;
  244.   end;
  245. end;
  246.  
  247. procedure TSeriesDataSet.InternalHandleException;
  248. begin
  249.   Application.HandleException(Self);
  250. end;
  251.  
  252. procedure TSeriesDataSet.InternalGotoBookmark(Bookmark: Pointer);
  253. var Index: Integer;
  254. begin
  255.   Index := FBookMarks.IndexOf(Pointer(PInteger(Bookmark)^));
  256.   if Index <> -1 then
  257.     FCurRec := Index
  258.   else
  259.     DatabaseError('Bookmark not found');
  260. end;
  261.  
  262. procedure TSeriesDataSet.InternalSetToRecord(Buffer: PChar);
  263. begin
  264.   InternalGotoBookmark(@PRecInfo(Buffer + RecInfoOfs).Bookmark);
  265. end;
  266.  
  267. function TSeriesDataSet.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
  268. begin
  269.   Result := PRecInfo(Buffer + RecInfoOfs).BookmarkFlag;
  270. end;
  271.  
  272. procedure TSeriesDataSet.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
  273. begin
  274.   PRecInfo(Buffer + RecInfoOfs).BookmarkFlag := Value;
  275. end;
  276.  
  277. procedure TSeriesDataSet.GetBookmarkData(Buffer: PChar; Data: Pointer);
  278. begin
  279.   PInteger(Data)^ := PRecInfo(Buffer + RecInfoOfs).Bookmark;
  280. end;
  281.  
  282. procedure TSeriesDataSet.SetBookmarkData(Buffer: PChar; Data: Pointer);
  283. begin
  284.   PRecInfo(Buffer + RecInfoOfs).Bookmark := PInteger(Data)^;
  285. end;
  286.  
  287. function TSeriesDataSet.GetRecordSize: Word;
  288. begin
  289.   if Assigned(FSeries) then result:=SizeOf(TSeriesPoint)
  290.                        else result:=0;
  291. end;
  292.  
  293. function TSeriesDataSet.AllocRecordBuffer: PChar;
  294. begin
  295.   GetMem(Result, RecBufSize);
  296. end;
  297.  
  298. procedure TSeriesDataSet.FreeRecordBuffer(var Buffer: PChar);
  299. begin
  300.   FreeMem(Buffer, RecBufSize);
  301. end;
  302.  
  303. function TSeriesDataSet.GetRecord(Buffer: PChar; GetMode: TGetMode;
  304.   DoCheck: Boolean): TGetResult;
  305. var t:Integer;
  306. begin
  307.   result:=grError;
  308.   if Assigned(FSeries) then
  309.   begin
  310.     if FSeries.Count < 1 then Result := grEOF
  311.     else
  312.     begin
  313.       Result := grOK;
  314.       case GetMode of
  315.         gmNext: if FCurRec >= RecordCount - 1  then Result := grEOF
  316.                                                  else Inc(FCurRec);
  317.        gmPrior: if FCurRec <= 0 then Result := grBOF
  318.                                   else Dec(FCurRec);
  319.      gmCurrent: if (FCurRec < 0) or (FCurRec >= RecordCount) then
  320.                    Result := grError;
  321.       end;
  322.       if Result = grOK then
  323.       begin
  324.         With PSeriesPoint(Buffer)^ do
  325.         begin
  326.           Color:=FSeries.ValueColor[FCurRec];
  327.           X:=FSeries.XValue[FCurRec];
  328.           ALabel:=FSeries.XLabel[FCurRec];
  329.           for t:=1 to FSeries.ValuesLists.Count-1 do
  330.               Values[t-1]:=FSeries.ValuesLists[t][FCurRec];
  331.         end;
  332.         with PRecInfo(Buffer + RecInfoOfs)^ do
  333.         begin
  334.           BookmarkFlag := bfCurrent;
  335.           Bookmark := Integer(FBookMarks[FCurRec]);
  336.         end;
  337.       end else
  338.         if (Result = grError) and DoCheck then DatabaseError('No Records');
  339.     end;
  340.   end
  341.   else if DoCheck then DatabaseError('No Records');
  342. end;
  343.  
  344. procedure TSeriesDataSet.InternalInitRecord(Buffer: PChar);
  345. begin
  346.   FillChar(Buffer^, RecordSize, 0);
  347. end;
  348.  
  349. function TSeriesDataSet.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
  350.  
  351.    Function GetSeriesValue(AList:TChartValueList):Double;
  352.    var t:Integer;
  353.    begin
  354.      if AList=FSeries.XValues then result:=PSeriesPoint(ActiveBuffer)^.X
  355.      else
  356.      begin
  357.        result:=0;
  358.        for t:=1 to FSeries.ValuesLists.Count-1 do
  359.        if AList=FSeries.ValuesLists[t] then
  360.        begin
  361.          result:=PSeriesPoint(ActiveBuffer)^.Values[t-1];
  362.          break;
  363.        end;
  364.      end;
  365.      if AList.DateTime then result:=TimeStampToMSecs(DateTimeToTimeStamp(result));
  366.    end;
  367.  
  368. begin
  369.   Result :=True;
  370.   if (ActiveBuffer<>nil) then
  371.   Case Field.FieldNo of
  372.     1: PInteger(Buffer)^:=PSeriesPoint(ActiveBuffer)^.Color;
  373.     2: PFloat(Buffer)^:=GetSeriesValue(FSeries.XValues);
  374.     3: PFloat(Buffer)^:=GetSeriesValue(FSeries.YValues);
  375.     4: begin
  376.          StrPCopy(Buffer, PSeriesPoint(ActiveBuffer)^.ALabel);
  377.          result := PChar(Buffer)^ <> #0;
  378.        end;
  379.     else
  380.     begin
  381.       PFloat(Buffer)^:=GetSeriesValue(FSeries.ValuesLists[Field.FieldNo-3]);
  382.     end;
  383.   end
  384.   else result:=False;
  385. end;
  386.  
  387. procedure TSeriesDataSet.SetFieldData(Field: TField; Buffer: Pointer);
  388.  
  389.    Function GetValue(IsDateTime:Boolean):Double;
  390.    begin
  391.      result:=PFloat(Buffer)^;
  392.      if IsDateTime then result:=TimeStampToDateTime(MSecsToTimeStamp(result));
  393.    end;
  394.  
  395. begin
  396.   if (ActiveBuffer<>nil) then
  397.   Case Field.FieldNo of
  398.     1: PSeriesPoint(ActiveBuffer)^.Color:=PInteger(Buffer)^;
  399.     2: PSeriesPoint(ActiveBuffer)^.X:=GetValue(FSeries.XValues.DateTime);
  400.     3: PSeriesPoint(ActiveBuffer)^.Values[0]:=GetValue(FSeries.YValues.DateTime);
  401.     4: PSeriesPoint(ActiveBuffer)^.ALabel:=PChar(Buffer);
  402.   else
  403.     PSeriesPoint(ActiveBuffer)^.Values[Field.FieldNo-4]:=GetValue(FSeries.ValuesLists[Field.FieldNo-3].DateTime);
  404.   end;
  405.   DataEvent(deFieldChange, Longint(Field));
  406. end;
  407.  
  408. procedure TSeriesDataSet.InternalFirst;
  409. begin
  410.   FCurRec := -1;
  411. end;
  412.  
  413. procedure TSeriesDataSet.InternalLast;
  414. begin
  415.   FCurRec := FSeries.Count;
  416. end;
  417.  
  418. Procedure TSeriesDataSet.AddSeriesPoint(Buffer:Pointer; ABookMark:Integer);
  419. var t,tmp:Integer;
  420. begin
  421.   With PSeriesPoint(Buffer)^ do
  422.   begin
  423.     tmp:=FSeries.AddXY(X,Values[0],ALabel,Color);
  424.     for t:=2 to FSeries.ValuesLists.Count-1 do
  425.         FSeries.ValuesLists[t].TempValue:=Values[t-1];
  426.     FSeries.AddValue(tmp);
  427.   end;
  428.   FBookMarks.Add(Pointer(ABookMark));
  429. end;
  430.  
  431. procedure TSeriesDataSet.InternalPost;
  432. var t:Integer;
  433. begin
  434.   if State = dsEdit then
  435.   With PSeriesPoint(ActiveBuffer)^ do
  436.   Begin
  437.     FSeries.ValueColor[FCurRec]:=Color;
  438.     FSeries.XValue[FCurRec]:=X;
  439.     FSeries.YValue[FCurRec]:=Values[0];
  440.     FSeries.XLabel[FCurRec]:=ALabel;
  441.     for t:=2 to FSeries.ValuesLists.Count-1 do
  442.         FSeries.ValuesLists[t][FCurRec]:=Values[t-1];
  443.   end
  444.   else
  445.   begin
  446.     Inc(FLastBookmark);
  447.     AddSeriesPoint(ActiveBuffer,FLastBookMark);
  448.   end;
  449. end;
  450.  
  451. procedure TSeriesDataSet.InternalAddRecord(Buffer: Pointer; Append: Boolean);
  452. begin
  453.   Inc(FLastBookmark);
  454.   if Append then InternalLast;
  455.   AddSeriesPoint(Buffer,FLastBookmark);
  456. end;
  457.  
  458. procedure TSeriesDataSet.InternalDelete;
  459. begin
  460.   FSeries.Delete(FCurRec);
  461.   FBookMarks.Delete(FCurRec);
  462.   if FCurRec >= RecordCount then Dec(FCurRec);
  463. end;
  464.  
  465. function TSeriesDataSet.GetRecordCount: Longint;
  466. begin
  467.   Result := FSeries.Count;
  468. end;
  469.  
  470. function TSeriesDataSet.GetRecNo: Longint;
  471. begin
  472.   UpdateCursorPos;
  473.   if (FCurRec = -1) and (RecordCount > 0) then
  474.      Result := 1
  475.   else
  476.      Result := FCurRec + 1;
  477. end;
  478.  
  479. procedure TSeriesDataSet.SetRecNo(Value: Integer);
  480. begin
  481.   if (Value >= 0) and (Value <= RecordCount) then
  482.   begin
  483.     FCurRec := Value - 1;
  484.     Resync([]);
  485.   end;
  486. end;
  487.  
  488. end.
  489.